package com.pxxy.toturial.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import org.slf4j.Logger;

import java.util.Arrays;

/******************
 * @Author yejf
 * @Description TODO
 */
@Component
@Aspect
@Order(1)   //如果有多个 Advice时，通过Order来指定他们的执行的顺序，数字越小，优先级越高.
public class LogAdvice {

    private static final Logger log = LoggerFactory.getLogger(LogAdvice.class);

    //定义 PointCut
    @Pointcut("execution(* com.pxxy.toturial.service.impl.CalcServiceImpl.*(..))")
    public void pointcut() {
        // nothing!
    }

    //@Before(value = "execution(* com.pxxy.toturial.service.impl.CalcServiceImpl.*(..))")
    @Before("pointcut()")
    public void beforeLog(JoinPoint jp) {
        final Object target = jp.getTarget();
        final Signature signature = jp.getSignature();
        //获取目标方法的参数
        final Object[] args = jp.getArgs();
        //此处的代码将在目标方法被调用之前 调用。
        log.debug(String.format("在目标类型【%s】的[%s]方法,参数是：[%s]执行之前...",
                        target.getClass().getName(), signature.getName(), Arrays.toString(args)));
    }

    //@After(value = "execution(* com.pxxy.toturial.service.impl.CalcServiceImpl.*(..))")
    @After("pointcut()")
    public void afterLog(JoinPoint jp) {
        final Object target = jp.getTarget();
        final Signature signature = jp.getSignature();
        //此处的代码将在目标方法被调用之前 调用。
        log.debug(String.format("在目标类型【%s】的[%s]方法执行之后...",
                target.getClass().getName(), signature.getName()));
    }

    @AfterReturning(value = "pointcut()", returning = "result")
    public void afterReturning(JoinPoint jp, Object result) {
        final Object target = jp.getTarget();
        final Signature signature = jp.getSignature();
        //获取目标方法的参数
        final Object[] args = jp.getArgs();
        log.debug(String.format("目标方法[%s]执行成功，结果是：[%s]",
                signature.getName(),String.valueOf(result)));
    }

    @AfterThrowing(value = "pointcut()", throwing = "e")
    public void afterThrowing(JoinPoint jp, Exception e) {
        log.debug(String.format("目标方法[%s]执行失败，异常是：[%s]",
                jp.getSignature().getName(),e.getMessage()));
    }


    @Around(value = "execution(public * com.pxxy.toturial.service..CalcServiceImpl.divide(double,int))")
    public void around(ProceedingJoinPoint pjp) {
        System.out.println(pjp.getClass());
        //获取相关的信息
        final Object target = pjp.getTarget();
        final Signature signature = pjp.getSignature();
        System.out.println(signature.getClass());
        final Object[] args = pjp.getArgs();
        //只有当调用了 pjp.proceed方法后，Spring框架才会把调用权给到目标方法。
        log.debug(String.format("在around方法中：目标方法[%s]",signature.getName()));
        //判断
        if(Integer.parseInt(String.valueOf(args[1])) <= 0) {
            //不去执行目标方法
            System.out.println("由于第二个参数是0，所以，不去执行目标方法...");
        } else {
            //执行目标方法
            Object result = null;
            try {
                //before
                System.out.println("目标方法执行之前："+signature.getName());
                //我们可以在这里模拟一组新的参数【注：参数个数一定要与原来的参数个数保持一致】
                //Object[] args_new = new Object[]{Double.valueOf(100), Integer.valueOf(10)};
                result = pjp.proceed();

                //afterReturning
                System.out.println("目标方法执行完后");
            } catch (Throwable throwable) {
                //afterThrowing
                System.out.println("目标方法出异常了");
                throwable.printStackTrace();
            }
            //after
            System.out.println("result = " + result);
        }
    }
}
